import java.io.*;

public class SharedObject implements Serializable, SharedObject_itf {

	public enum SharedObjectLock {
		NL, // NO_LOCK
		RLC, // READ_LOCK_CACHED
		RLT, // READ_LOCK_TAKEN
		WLC, // WRITE_LOCK_CACHED
		WLT, // WRITE_LOCK_TAKEN
		RLT_WLC
		// READ_LOCK_TAKEN_AND_WRITE_LOCK_CACHED
	}

	Object obj;
	int id;
	SharedObjectLock lock;

	boolean waitCondition;
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public SharedObject(int id, Object obj) {
		this.id = id;
		this.obj = obj;
		lock = SharedObjectLock.NL;
		waitCondition = false;

	}

	// invoked by the user program on the client node
	public void lock_read() {
		boolean request = false;
		synchronized (this) {
			while (waitCondition)
				try {
					wait();
				} catch (Exception e) {
				}

			switch (lock) {
			case NL:
				request = true;
				this.lock = SharedObjectLock.RLT;
				break;
			case RLC:
				this.lock = SharedObjectLock.RLT;
				break;
			case WLC:
				this.lock = SharedObjectLock.RLT_WLC;
				break;
			default:
				break;
			}
		}

		if (request)
			this.obj = Client.lock_read(id);

	}

	// ivoked by the user program on the client node
	public void lock_write() {
		boolean request = false;
		synchronized (this) {
			
			while (waitCondition)
				try {
					wait();
				} catch (Exception e) {
				}

			switch (lock) {
			case NL:
				request = true;
				this.lock = SharedObjectLock.WLT;
				break;
			case RLC:
				request = true;
				this.lock = SharedObjectLock.WLT;
				break;
			case WLC:
				this.lock = SharedObjectLock.WLT;
				break;
			default:
				break;
			}
		}
		if (request)
			this.obj = Client.lock_write(id);

	}

	// invoked by the user program on the client node
	public synchronized void unlock() {

		switch (lock) {
		case RLT:
			lock = SharedObjectLock.RLC;
			break;
		case WLT:
			lock = SharedObjectLock.WLC;
			break;
		case RLT_WLC:
			lock = SharedObjectLock.WLC;
			break;
		default:
			break;
		}

		try {
			notify();
		} catch (Exception e) {
		}
	}

	// callback invoked remotely by the server
	public synchronized Object reduce_lock() {

		waitCondition = true;
		switch (lock) {
		case WLT:
			while (lock == SharedObjectLock.WLT)
				try {
					wait();
				} catch (Exception e) {
				}
			lock = SharedObjectLock.RLC;
			break;
		case WLC:
			lock = SharedObjectLock.RLC;
			break;
		case RLT_WLC:
			while (lock == SharedObjectLock.RLT_WLC)
				try {
					wait();
				} catch (Exception e) {
				}
			lock = SharedObjectLock.RLC;
			break;
		default:
			break;

		}
		waitCondition = false;
		try {
			notify();
		} catch (Exception e) {
		}
		return obj;
	}

	// callback invoked remotely by the server
	public synchronized void invalidate_reader() {

		waitCondition = true;
		switch (lock) {
		case RLT:
			while (lock == SharedObjectLock.RLT)
				try {
					wait();
				} catch (Exception e) {
				}
			lock = SharedObjectLock.NL;
			break;
		case RLC:
			lock = SharedObjectLock.NL;
			break;
		default:
			break;
		}

		waitCondition = false;
		try {
			notify();
		} catch (Exception e) {
		}

	}

	// callback invoked remotely by the server
	public synchronized Object invalidate_writer() {

		waitCondition = true;
		switch (lock) {
		case WLT:
			while (lock == SharedObjectLock.WLT)
				try {
					wait();
				} catch (Exception e) {
				}
			lock = SharedObjectLock.NL;
			break;
		case WLC:
			lock = SharedObjectLock.NL;
			break;
		case RLT_WLC:
			while (lock == SharedObjectLock.RLT_WLC)
				try {
					wait();
				} catch (Exception e) {
				}
			lock = SharedObjectLock.NL;
			break;
		default:
			break;
		}

		waitCondition = false;
		try {
			notify();
		} catch (Exception e) {
		}
		return obj;
	}
}
